#ifndef __INTELLIGENT_XML_PARSER_H__
  #define __INTELLIGENT_XML_PARSER_H__

#include <fcntl.h>
#include <sys/stat.h>

#ifdef _WIN32
  #include <io.h>
#endif

#include "exceptions.h"
#include "xml_parser.h"

//! Helper class for parsing XML files only if needed.

/*!
The given XML file will be parsed only if it is modified since the last parse. The xml_node will stay in
memory.

Implementation date: 2008

Usage:

\code
intelligent_xml_parser ixp("options.xml");
const xml_node *xn = 0;

for (int i = 0; i < 10; ++i) {
  xn = &(ixp.get()); // 'options.xml' will be parsed only if it is modified
  // ... use xn here
}
\endcode
*/

class intelligent_xml_parser {
private:
  xml_node xn;
  const string xml_file_name;
  time_t last_modification;

public:
  //! releases the xml_node and resets the 'last_modification'
  void release() {
    xn.destroy();
    last_modification = 0;
  }

  //! returns the xml_node which is never null and is always up-to-date (may throw an exception)
  const xml_node &get() {
    struct stat buf;
    const int f = open(xml_file_name.c_str(), O_RDONLY);

    if (f != -1) {
      fstat(f, &buf);
      close(f);

      if (buf.st_mtime != last_modification) {
        last_modification = buf.st_mtime;

        xml_parser xp;
        xp.parse_file(xml_file_name, &xn);
      } // if
    } else {
      string msg = "File '%1' not found!";
      str::format(msg, arg<string>(xml_file_name));
      throw xml_exception(msg);
    } // else

    return this->xn;
  }

  //! constructor
  intelligent_xml_parser(const string &xml_file_name) : xml_file_name(xml_file_name), last_modification(0) {
    // nothing to do
  }

  //! destructor
  virtual ~intelligent_xml_parser() {
    // nothing to do
  }
};

#endif
